"""
偏好分析引擎服务实现

提供用户偏好分析和管理功能，包括：
- 用户偏好提取算法
- 偏好变化检测逻辑
- 偏好模型更新机制
- 个性化推荐生成
"""
import json
import math
from typing import List, Dict, Any, Optional, Tuple, Set
from datetime import datetime, timedelta
from dataclasses import asdict, replace
from collections import defaultdict, Counter

from ..models.analysis_models import (
    UserBehavior, UserPreferences, Context, Recommendations, 
    InterfaceConfig, PreferenceChange
)
from .user_behavior_service import UserBehaviorService


class PreferenceAnalysisService:
    """偏好分析引擎服务"""
    
    def __init__(self, behavior_service: Optional[UserBehaviorService] = None):
        self.behavior_service = behavior_service or UserBehaviorService()
        
        # 偏好数据存储
        self.user_preferences: Dict[str, UserPreferences] = {}
        self.preference_history: Dict[str, List[UserPreferences]] = defaultdict(list)
        self.preference_changes: Dict[str, List[PreferenceChange]] = defaultdict(list)
        
        # 偏好分析配置
        self.analysis_config = {
            'min_behaviors_for_analysis': 20,
            'preference_update_threshold': 0.15,  # 15%变化阈值
            'change_detection_window_days': 30,
            'similarity_threshold': 0.8,
            'clustering_min_samples': 5
        }
        
        # 偏好权重配置
        self.preference_weights = {
            'frequency': 0.3,      # 使用频率权重
            'success_rate': 0.25,  # 成功率权重
            'duration': 0.2,       # 使用时长权重
            'recency': 0.15,       # 最近使用权重
            'feedback': 0.1        # 用户反馈权重
        }
        
        # 学习风格定义
        self.learning_styles = {
            'visual': ['visualization', 'chart_generation', 'diagram_view'],
            'analytical': ['statistical_analysis', 'data_mining', 'pattern_recognition'],
            'experimental': ['experiment_design', 'parameter_tuning', 'hypothesis_testing'],
            'collaborative': ['document_sharing', 'comment_discussion', 'peer_review'],
            'systematic': ['step_by_step_guide', 'template_usage', 'structured_workflow']
        }
        
        # 专业水平指标
        self.expertise_indicators = {
            'beginner': {
                'help_usage_ratio': 0.3,
                'error_rate': 0.2,
                'advanced_feature_usage': 0.1
            },
            'intermediate': {
                'help_usage_ratio': 0.15,
                'error_rate': 0.1,
                'advanced_feature_usage': 0.4
            },
            'advanced': {
                'help_usage_ratio': 0.05,
                'error_rate': 0.05,
                'advanced_feature_usage': 0.7
            }
        }
    
    async def extract_user_preferences(self, user_id: str) -> UserPreferences:
        """提取用户偏好"""
        try:
            # 获取用户行为数据
            protected_user_id = await self.behavior_service._protect_user_id(user_id)
            
            if protected_user_id not in self.behavior_service.behavior_data:
                return UserPreferences()
            
            behaviors = self.behavior_service.behavior_data[protected_user_id]
            
            if len(behaviors) < self.analysis_config['min_behaviors_for_analysis']:
                return UserPreferences()
            
            # 提取各种偏好维度
            preferred_methods = await self._extract_method_preferences(behaviors)
            interface_preferences = await self._extract_interface_preferences(behaviors)
            workflow_patterns = await self._extract_workflow_patterns(behaviors)
            learning_style = await self._determine_learning_style(behaviors)
            expertise_level = await self._assess_expertise_level(behaviors)
            
            # 创建偏好对象
            preferences = UserPreferences(
                preferred_methods=preferred_methods,
                interface_preferences=interface_preferences,
                workflow_patterns=workflow_patterns,
                learning_style=learning_style,
                expertise_level=expertise_level
            )
            
            # 存储偏好
            self.user_preferences[user_id] = preferences
            
            return preferences
            
        except Exception as e:
            print(f"提取用户偏好失败: {e}")
            return UserPreferences()
    
    async def _extract_method_preferences(self, behaviors: List[UserBehavior]) -> List[str]:
        """提取方法偏好"""
        method_scores = {}
        
        for behavior in behaviors:
            method = behavior.action_type
            
            # 计算偏好分数
            frequency_score = 1.0  # 每次使用得1分
            success_score = 2.0 if behavior.success else 0.0
            duration_score = min(2.0, behavior.duration_seconds / 60.0)  # 时长分数，最高2分
            
            # 最近使用加权
            days_ago = (datetime.now() - behavior.created_at).days
            recency_score = max(0.1, 1.0 - (days_ago / 30.0))  # 30天内线性衰减
            
            # 用户反馈加权
            feedback_score = 1.0
            if behavior.user_feedback:
                # 简单的情感分析
                positive_words = ['好', '棒', '有用', '帮助', '满意', '喜欢']
                negative_words = ['差', '糟', '无用', '困难', '不满', '讨厌']
                
                feedback_text = behavior.user_feedback.lower()
                positive_count = sum(1 for word in positive_words if word in feedback_text)
                negative_count = sum(1 for word in negative_words if word in feedback_text)
                
                if positive_count > negative_count:
                    feedback_score = 1.5
                elif negative_count > positive_count:
                    feedback_score = 0.5
            
            # 综合评分
            total_score = (
                self.preference_weights['frequency'] * frequency_score +
                self.preference_weights['success_rate'] * success_score +
                self.preference_weights['duration'] * duration_score +
                self.preference_weights['recency'] * recency_score +
                self.preference_weights['feedback'] * feedback_score
            )
            
            method_scores[method] = method_scores.get(method, 0) + total_score
        
        # 返回评分最高的方法
        sorted_methods = sorted(method_scores.items(), key=lambda x: x[1], reverse=True)
        return [method for method, score in sorted_methods[:10]]  # 返回前10个偏好方法
    
    async def _extract_interface_preferences(self, behaviors: List[UserBehavior]) -> Dict[str, Any]:
        """提取界面偏好"""
        interface_prefs = {
            'preferred_view_mode': 'default',
            'information_density': 'medium',
            'interaction_style': 'standard',
            'notification_frequency': 'normal'
        }
        
        # 分析界面相关行为
        ui_behaviors = [b for b in behaviors if b.action_type in [
            'page_view', 'menu_click', 'tab_switch', 'settings_change'
        ]]
        
        if not ui_behaviors:
            return interface_prefs
        
        # 分析视图模式偏好
        view_modes = defaultdict(int)
        for behavior in ui_behaviors:
            if 'view_mode' in behavior.context:
                view_modes[behavior.context['view_mode']] += 1
        
        if view_modes:
            interface_prefs['preferred_view_mode'] = max(view_modes.items(), key=lambda x: x[1])[0]
        
        # 分析信息密度偏好
        avg_session_actions = len(behaviors) / max(1, len(set(b.created_at.date() for b in behaviors)))
        if avg_session_actions > 20:
            interface_prefs['information_density'] = 'high'
        elif avg_session_actions < 10:
            interface_prefs['information_density'] = 'low'
        
        # 分析交互风格
        quick_actions = sum(1 for b in behaviors if b.duration_seconds < 5)
        total_actions = len(behaviors)
        
        if quick_actions / total_actions > 0.7:
            interface_prefs['interaction_style'] = 'efficient'
        elif quick_actions / total_actions < 0.3:
            interface_prefs['interaction_style'] = 'detailed'
        
        return interface_prefs
    
    async def _extract_workflow_patterns(self, behaviors: List[UserBehavior]) -> List[str]:
        """提取工作流模式"""
        # 按时间排序行为
        sorted_behaviors = sorted(behaviors, key=lambda x: x.created_at)
        
        # 提取行为序列
        sequences = []
        current_sequence = []
        
        for i, behavior in enumerate(sorted_behaviors):
            current_sequence.append(behavior.action_type)
            
            # 如果时间间隔超过30分钟或达到序列长度限制，结束当前序列
            if (i < len(sorted_behaviors) - 1 and 
                (sorted_behaviors[i + 1].created_at - behavior.created_at).total_seconds() > 1800) or \
               len(current_sequence) >= 10:
                
                if len(current_sequence) >= 3:  # 至少3个步骤才算有效序列
                    sequences.append(tuple(current_sequence))
                current_sequence = []
        
        # 添加最后一个序列
        if len(current_sequence) >= 3:
            sequences.append(tuple(current_sequence))
        
        # 统计序列频率
        sequence_counts = Counter(sequences)
        
        # 提取常见模式
        common_patterns = []
        for sequence, count in sequence_counts.most_common(5):
            if count >= 2:  # 至少出现2次
                pattern_name = f"{sequence[0]}->{sequence[-1]}"
                common_patterns.append(pattern_name)
        
        return common_patterns
    
    async def _determine_learning_style(self, behaviors: List[UserBehavior]) -> str:
        """确定学习风格"""
        style_scores = defaultdict(float)
        
        for behavior in behaviors:
            action_type = behavior.action_type
            
            # 根据行为类型计算各种学习风格的分数
            for style, actions in self.learning_styles.items():
                if any(action in action_type for action in actions):
                    # 成功的行为得更高分数
                    score = 2.0 if behavior.success else 1.0
                    
                    # 最近的行为得更高权重
                    days_ago = (datetime.now() - behavior.created_at).days
                    recency_weight = max(0.1, 1.0 - (days_ago / 60.0))
                    
                    style_scores[style] += score * recency_weight
        
        # 返回得分最高的学习风格
        if style_scores:
            return max(style_scores.items(), key=lambda x: x[1])[0]
        
        return "balanced"  # 默认平衡型
    
    async def _assess_expertise_level(self, behaviors: List[UserBehavior]) -> str:
        """评估专业水平"""
        total_behaviors = len(behaviors)
        if total_behaviors == 0:
            return "beginner"
        
        # 计算各种指标
        help_behaviors = sum(1 for b in behaviors if 'help' in b.action_type.lower())
        help_ratio = help_behaviors / total_behaviors
        
        failed_behaviors = sum(1 for b in behaviors if not b.success)
        error_rate = failed_behaviors / total_behaviors
        
        # 高级功能使用情况
        advanced_actions = [
            'experiment_design', 'parameter_optimization', 'statistical_analysis',
            'knowledge_graph', 'quality_assessment', 'improvement_suggestion'
        ]
        advanced_usage = sum(1 for b in behaviors if any(action in b.action_type for action in advanced_actions))
        advanced_ratio = advanced_usage / total_behaviors
        
        # 根据指标判断专业水平
        for level, thresholds in self.expertise_indicators.items():
            if (help_ratio <= thresholds['help_usage_ratio'] and
                error_rate <= thresholds['error_rate'] and
                advanced_ratio >= thresholds['advanced_feature_usage']):
                return level
        
        return "intermediate"  # 默认中级
    
    async def detect_preference_changes(self, user_id: str) -> List[PreferenceChange]:
        """检测偏好变化"""
        try:
            if user_id not in self.preference_history:
                return []
            
            history = self.preference_history[user_id]
            if len(history) < 2:
                return []
            
            current_prefs = history[-1]
            previous_prefs = history[-2]
            
            changes = []
            
            # 检测方法偏好变化
            current_methods = set(current_prefs.preferred_methods)
            previous_methods = set(previous_prefs.preferred_methods)
            
            if current_methods != previous_methods:
                # 计算变化程度
                intersection = current_methods.intersection(previous_methods)
                union = current_methods.union(previous_methods)
                similarity = len(intersection) / len(union) if union else 1.0
                
                if similarity < self.analysis_config['similarity_threshold']:
                    change = PreferenceChange(
                        change_type="method_preferences",
                        old_value=list(previous_methods),
                        new_value=list(current_methods),
                        confidence=1.0 - similarity
                    )
                    changes.append(change)
            
            # 检测界面偏好变化
            for key, current_value in current_prefs.interface_preferences.items():
                previous_value = previous_prefs.interface_preferences.get(key)
                if previous_value and current_value != previous_value:
                    change = PreferenceChange(
                        change_type=f"interface_{key}",
                        old_value=previous_value,
                        new_value=current_value,
                        confidence=0.8
                    )
                    changes.append(change)
            
            # 检测学习风格变化
            if current_prefs.learning_style != previous_prefs.learning_style:
                change = PreferenceChange(
                    change_type="learning_style",
                    old_value=previous_prefs.learning_style,
                    new_value=current_prefs.learning_style,
                    confidence=0.9
                )
                changes.append(change)
            
            # 检测专业水平变化
            if current_prefs.expertise_level != previous_prefs.expertise_level:
                change = PreferenceChange(
                    change_type="expertise_level",
                    old_value=previous_prefs.expertise_level,
                    new_value=current_prefs.expertise_level,
                    confidence=0.95
                )
                changes.append(change)
            
            # 存储变化记录
            self.preference_changes[user_id].extend(changes)
            
            return changes
            
        except Exception as e:
            print(f"检测偏好变化失败: {e}")
            return []
    
    async def update_preference_model(self, user_id: str, force_update: bool = False) -> bool:
        """更新偏好模型"""
        try:
            # 提取最新偏好
            new_preferences = await self.extract_user_preferences(user_id)
            
            if user_id in self.user_preferences and not force_update:
                # 检查是否需要更新
                current_prefs = self.user_preferences[user_id]
                
                # 计算偏好相似度
                similarity = await self._calculate_preference_similarity(current_prefs, new_preferences)
                
                if similarity > (1.0 - self.analysis_config['preference_update_threshold']):
                    return False  # 变化不够大，不需要更新
            
            # 保存历史记录
            if user_id in self.user_preferences:
                self.preference_history[user_id].append(self.user_preferences[user_id])
                
                # 限制历史记录长度
                if len(self.preference_history[user_id]) > 10:
                    self.preference_history[user_id] = self.preference_history[user_id][-10:]
            
            # 更新偏好
            self.user_preferences[user_id] = new_preferences
            
            # 检测变化
            await self.detect_preference_changes(user_id)
            
            return True
            
        except Exception as e:
            print(f"更新偏好模型失败: {e}")
            return False
    
    async def _calculate_preference_similarity(self, prefs1: UserPreferences, prefs2: UserPreferences) -> float:
        """计算偏好相似度"""
        similarities = []
        
        # 方法偏好相似度
        methods1 = set(prefs1.preferred_methods)
        methods2 = set(prefs2.preferred_methods)
        
        if methods1 or methods2:
            intersection = methods1.intersection(methods2)
            union = methods1.union(methods2)
            method_similarity = len(intersection) / len(union) if union else 1.0
            similarities.append(method_similarity)
        
        # 界面偏好相似度
        interface_matches = 0
        interface_total = 0
        
        all_keys = set(prefs1.interface_preferences.keys()).union(set(prefs2.interface_preferences.keys()))
        for key in all_keys:
            interface_total += 1
            if (key in prefs1.interface_preferences and 
                key in prefs2.interface_preferences and
                prefs1.interface_preferences[key] == prefs2.interface_preferences[key]):
                interface_matches += 1
        
        if interface_total > 0:
            interface_similarity = interface_matches / interface_total
            similarities.append(interface_similarity)
        
        # 学习风格相似度
        learning_similarity = 1.0 if prefs1.learning_style == prefs2.learning_style else 0.0
        similarities.append(learning_similarity)
        
        # 专业水平相似度
        expertise_similarity = 1.0 if prefs1.expertise_level == prefs2.expertise_level else 0.0
        similarities.append(expertise_similarity)
        
        # 返回平均相似度
        return sum(similarities) / len(similarities) if similarities else 0.0
    
    async def generate_personalized_recommendations(self, user_id: str, context: Context) -> Recommendations:
        """生成个性化推荐"""
        try:
            if user_id not in self.user_preferences:
                await self.update_preference_model(user_id)
            
            if user_id not in self.user_preferences:
                return Recommendations()
            
            preferences = self.user_preferences[user_id]
            
            # 基于偏好生成推荐
            recommended_actions = []
            confidence_scores = {}
            reasoning = []
            alternative_options = []
            
            # 基于偏好方法推荐
            for method in preferences.preferred_methods[:5]:
                if method not in context.current_task:  # 避免重复推荐当前任务
                    recommended_actions.append(f"使用{method}方法")
                    confidence_scores[f"使用{method}方法"] = 0.8
                    reasoning.append(f"基于您的使用历史，您偏好{method}方法")
            
            # 基于学习风格推荐
            if preferences.learning_style in self.learning_styles:
                style_actions = self.learning_styles[preferences.learning_style]
                for action in style_actions[:3]:
                    # 简化重复检查逻辑
                    action_name = f"尝试{action}功能"
                    if action_name not in recommended_actions:
                        recommended_actions.append(action_name)
                        confidence_scores[action_name] = 0.7
                        reasoning.append(f"根据您的{preferences.learning_style}学习风格推荐")
            
            # 基于专业水平推荐
            if preferences.expertise_level == "beginner":
                recommended_actions.append("查看入门指南")
                confidence_scores["查看入门指南"] = 0.9
                reasoning.append("基于您的专业水平，建议从基础功能开始")
                
                alternative_options.extend([
                    "观看教程视频",
                    "使用向导模式",
                    "查看示例项目"
                ])
            elif preferences.expertise_level == "advanced":
                recommended_actions.append("探索高级功能")
                confidence_scores["探索高级功能"] = 0.8
                reasoning.append("基于您的专业水平，可以尝试更高级的功能")
                
                alternative_options.extend([
                    "自定义工作流",
                    "使用API接口",
                    "参与功能测试"
                ])
            
            # 基于上下文推荐
            if context.time_constraints.get('urgent', False):
                recommended_actions.insert(0, "使用快速模式")
                confidence_scores["使用快速模式"] = 0.9
                reasoning.insert(0, "检测到时间紧急，推荐快速模式")
            
            return Recommendations(
                recommended_actions=recommended_actions[:10],  # 限制推荐数量
                confidence_scores=confidence_scores,
                reasoning=reasoning,
                alternative_options=alternative_options[:5]
            )
            
        except Exception as e:
            print(f"生成个性化推荐失败: {e}")
            return Recommendations()
    
    async def get_preference_analysis_report(self, user_id: str) -> Dict[str, Any]:
        """获取偏好分析报告"""
        try:
            if user_id not in self.user_preferences:
                return {'error': '用户偏好数据不存在'}
            
            preferences = self.user_preferences[user_id]
            changes = self.preference_changes.get(user_id, [])
            
            report = {
                'user_id': user_id,
                'analysis_date': datetime.now().isoformat(),
                'current_preferences': {
                    'preferred_methods': preferences.preferred_methods,
                    'interface_preferences': preferences.interface_preferences,
                    'workflow_patterns': preferences.workflow_patterns,
                    'learning_style': preferences.learning_style,
                    'expertise_level': preferences.expertise_level
                },
                'preference_stability': {
                    'total_changes': len(changes),
                    'recent_changes': len([c for c in changes if 
                                         (datetime.now() - c.detected_at).days <= 30]),
                    'change_types': list(set(c.change_type for c in changes))
                },
                'recommendations': {
                    'interface_optimization': await self._generate_interface_recommendations(preferences),
                    'workflow_optimization': await self._generate_workflow_recommendations(preferences),
                    'learning_path': await self._generate_learning_recommendations(preferences)
                }
            }
            
            return report
            
        except Exception as e:
            print(f"生成偏好分析报告失败: {e}")
            return {'error': '偏好分析报告生成失败'}
    
    async def _generate_interface_recommendations(self, preferences: UserPreferences) -> List[str]:
        """生成界面优化建议"""
        recommendations = []
        
        interface_prefs = preferences.interface_preferences
        
        if interface_prefs.get('information_density') == 'high':
            recommendations.append("启用紧凑视图模式以显示更多信息")
        elif interface_prefs.get('information_density') == 'low':
            recommendations.append("使用宽松布局以减少视觉负担")
        
        if interface_prefs.get('interaction_style') == 'efficient':
            recommendations.append("启用快捷键和批量操作功能")
        elif interface_prefs.get('interaction_style') == 'detailed':
            recommendations.append("显示详细的操作说明和确认对话框")
        
        return recommendations
    
    async def _generate_workflow_recommendations(self, preferences: UserPreferences) -> List[str]:
        """生成工作流优化建议"""
        recommendations = []
        
        # 基于工作流模式推荐
        if preferences.workflow_patterns:
            recommendations.append(f"创建常用工作流模板：{', '.join(preferences.workflow_patterns[:3])}")
        
        # 基于偏好方法推荐
        if len(preferences.preferred_methods) > 5:
            recommendations.append("将常用功能添加到快速访问工具栏")
        
        return recommendations
    
    async def _generate_learning_recommendations(self, preferences: UserPreferences) -> List[str]:
        """生成学习路径建议"""
        recommendations = []
        
        if preferences.expertise_level == "beginner":
            recommendations.extend([
                "完成基础功能教程",
                "参加新手训练营",
                "阅读用户手册"
            ])
        elif preferences.expertise_level == "intermediate":
            recommendations.extend([
                "探索高级分析功能",
                "学习自动化工作流",
                "参与社区讨论"
            ])
        elif preferences.expertise_level == "advanced":
            recommendations.extend([
                "贡献功能改进建议",
                "开发自定义插件",
                "指导新用户"
            ])
        
        return recommendations
    
    async def export_preference_data(self, user_id: str) -> Dict[str, Any]:
        """导出偏好数据"""
        try:
            export_data = {
                'user_id': user_id,
                'export_date': datetime.now().isoformat(),
                'current_preferences': None,
                'preference_history': [],
                'preference_changes': []
            }
            
            if user_id in self.user_preferences:
                export_data['current_preferences'] = asdict(self.user_preferences[user_id])
            
            if user_id in self.preference_history:
                export_data['preference_history'] = [
                    asdict(prefs) for prefs in self.preference_history[user_id]
                ]
            
            if user_id in self.preference_changes:
                export_data['preference_changes'] = [
                    asdict(change) for change in self.preference_changes[user_id]
                ]
            
            return export_data
            
        except Exception as e:
            print(f"导出偏好数据失败: {e}")
            return {'error': '偏好数据导出失败'}
    
    async def delete_preference_data(self, user_id: str) -> bool:
        """删除偏好数据"""
        try:
            if user_id in self.user_preferences:
                del self.user_preferences[user_id]
            
            if user_id in self.preference_history:
                del self.preference_history[user_id]
            
            if user_id in self.preference_changes:
                del self.preference_changes[user_id]
            
            return True
            
        except Exception as e:
            print(f"删除偏好数据失败: {e}")
            return False